/*-------------------------------------------------------------------------*/
/**
  @file		execrefine_filters.c
  @author	Renaud Wanchoor
  @date	July 2004
  @version	$Revision: 2.11 $
  @brief	filter functions of the execution time uncoarsening phase

  all functions must be defined according to ::FILTER_FN prototype
  
*/
/*--------------------------------------------------------------------------*/

#include "pagrid.h"
#include "execrefine_params.h"

/** \brief Filter Function for Kernighan Lin (cf thesis) */
int FilterKl(void* rctrl,int a,
	     int v,int from, int to, 
	     double deltaF, double deltaT, double deltaO,int dOflag){

  RefCtrl* ctrl = rctrl;
  double *exec  = ctrl->n->exec;
  double Tmax   = ctrl->tmax;
  double *temp  = ctrl->flow;
  double Tf     = exec[from];
  double Tt     = exec[to];  
  double Tx,deltaX,max,deltaM;

#if MOVE_ONCE
  if(ctrl->mvtxs[v] >= MOVE_ONCE)
    return 0;
#endif

  /* deltaF + exec[from] = 0 was error prone because of floating point operation errors */
  if(ABS(deltaF + exec[from])<1)
    return 0;
  
  if((temp[from] < temp[to]) && (ctrl->im > MAX_IM))
    return 0;
  
  if(dOflag){
    int x,i,istart,iend,w,prow;
    int nnpro = ctrl->n->npro;
    int* procs = ctrl->procs;
    int* gadjidx = ctrl->g->adjidx;
    int* gadjncy = ctrl->g->adjncy;
    int* gadjwgt = ctrl->g->adjwgt;
    int* gpro    = ctrl->g->pro;
    double **ratio = ctrl->n->ratio;

    for(i=0;i<nnpro;i++)
      procs[i] = 0;

    istart = gadjidx[v];
    iend   = gadjidx[v+1];

    for(i=istart;i<iend;i++){
      w = gadjncy[i];
      prow= gpro[w];

      if(prow == from || prow == to)
	continue;
      
      procs[prow] += gadjwgt[i];      
    }

    max = Tmax;

    for(x=0;x<nnpro;x++){
      if(x == from || x == to || procs[x] == 0)
	continue;
      Tx = exec[x];
      deltaX = procs[x] * (ratio[x][to] - ratio[x][from]);

      /*if(Tx > Tf && deltaX > 0)
	return 0;
      
      if(Tx <= Tf && Tx + deltaX > Tf)
      return 0;*/

      max = MAX(max,Tx + deltaX);            
    }
    
    max = MAX(max, Tf+deltaF);
    max = MAX(max, Tt+deltaT);    deltaM = max-Tmax;
  }else{
    max = MAX(Tf + deltaF,Tt + deltaT);
    max = MAX(Tmax,max);
    deltaM = max - Tmax;
  }

  if(deltaM > 0){    
    return 0;
  }

  return 1;
}

/** \brief Filter Function (moving from, moving to, cf thesis) */
int Filter(void* rctrl,int a,
	   int v, int from, int to, 
	   double deltaF, double deltaT, double deltaO,int dOflag){
  
  RefCtrl* ctrl = rctrl;
  double max;
  double BmaxX;
  double AmaxX;
  double deltaMX;
  double deltaX;
  double deltaM;
  double *exec  = ctrl->n->exec;
  double Tx;
  double Tf     = exec[from];
  double Tt     = exec[to];
  double Tmax   = ctrl->tmax;
  
#if MOVE_ONCE
  if(ctrl->mvtxs[v] >= MOVE_ONCE)
    return 0;
#endif

  if(abs(deltaF + exec[from])<1)
    return 0;
  
  if(Tf<Tt)
    return 0;
  
  if(deltaF>0)
    return 0;      
  
  if((Tt + deltaT >= Tf))
    return 0;
  
  /* compute deltamax */
  if(dOflag){
    int x,i,istart,iend,w,prow;
    int nnpro = ctrl->n->npro;
    int* procs = ctrl->procs;
    int* procon = ctrl->procon;
    int* gadjidx = ctrl->g->adjidx;
    int* gadjncy = ctrl->g->adjncy;
    int* gadjwgt = ctrl->g->adjwgt;
    int* gpro    = ctrl->g->pro;
    double **ratio = ctrl->n->ratio;

    for(i=0;i<nnpro;i++){
      procs[i] = 0;
      procon[i] = 0;
    }

    istart = gadjidx[v];
    iend   = gadjidx[v+1];

    for(i=istart;i<iend;i++){
      w = gadjncy[i];
      prow= gpro[w];

      if(prow == from || prow == to)
	continue;
      
      procs[prow] += gadjwgt[i];      
      procon[prow]++;
    }

    max   = Tmax;
    BmaxX = MAX(exec[from],exec[to]);
    AmaxX = MAX(exec[from]+deltaF,exec[to]+deltaT);
    
    for(x=0;x<nnpro;x++){
      if(x == from || x == to || procs[x] == 0)
	continue;
      Tx = exec[x];
      deltaX = procs[x] * (ratio[x][to] - ratio[x][from]);            

      max   = MAX(max,Tx + deltaX);  
      BmaxX = MAX(BmaxX,Tx);
      AmaxX = MAX(AmaxX,Tx+deltaX);
    }
    
    max     = MAX(max, Tf+deltaF);
    max     = MAX(max, Tt+deltaT);
    deltaM  = max-Tmax;
    deltaMX = AmaxX - BmaxX;    

  }else{
    max     = MAX(Tf + deltaF,Tt + deltaT);
    max     = MAX(Tmax,max);
    deltaM  = max - Tmax;
    deltaMX = deltaM;
  }

  if(deltaM > 0)
    return 0;   

  return 1;
}

/** \brief Filter Function for load balancing (cf thesis) */
int FilterDiffuse(void* rctrl,int a,
		  int v,int from, int to, 
		  double deltaF, double deltaT, double deltaO,int dOflag){
  double max;
  double deltaX;
  RefCtrl* ctrl = rctrl;
  double *exec  = ctrl->n->exec;
  double *temp  = ctrl->flow;
  double Tx;
  double Tf     = exec[from];
  double Tt     = exec[to];
  double Tmax   = ctrl->tmax;
  double Tmean  = ctrl->tmean;
  double deltaM;

#if MOVE_ONCE
  if(ctrl->mvtxs[v] >= MOVE_ONCE)
    return 0;
#endif

  if(ABS(deltaF + exec[from])<1)
    return 0;
  
  if(temp[from] <= temp[to])
    return 0;
  
  if(deltaF>0)
    return 0;  
  
  if(Tt + deltaT > Tmean)
    return 0;

  /* compute deltamax */
  if(dOflag){
    int x,i,istart,iend,w,prow;
    int nnpro = ctrl->n->npro;
    int* procs = ctrl->procs;
    int* gadjidx = ctrl->g->adjidx;
    int* gadjncy = ctrl->g->adjncy;
    int* gadjwgt = ctrl->g->adjwgt;
    int* gpro    = ctrl->g->pro;
    double **ratio = ctrl->n->ratio;

    for(i=0;i<nnpro;i++)
      procs[i] = 0;

    istart = gadjidx[v];
    iend   = gadjidx[v+1];

    for(i=istart;i<iend;i++){
      w = gadjncy[i];
      prow= gpro[w];

      if(prow == from || prow == to)
	continue;
      
      procs[prow] += gadjwgt[i];            
    }

    max = Tmax;

    for(x=0;x<nnpro;x++){
      if(x == from || x == to || procs[x] == 0)
	continue;
      Tx = exec[x];
      deltaX = procs[x] * (ratio[x][to] - ratio[x][from]);      

      max = MAX(max,Tx + deltaX);            
    }
    
    max = MAX(max, Tf+deltaF);
    max = MAX(max, Tt+deltaT);
    deltaM = max-Tmax;
  }else{
    max = MAX(Tf + deltaF,Tt + deltaT);
    max = MAX(Tmax,max);
    deltaM = max - Tmax;
  }

  if(deltaM > 0)
    return 0;

  return 1;
}
